package xushuo.dao.service.tools.weixin;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import xushuo.dao.entity.weixin.menu.Menu;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import xushuo.dao.entity.weixin.token.AccessToken;
import xushuo.dao.service.token.AccessTokenService;
import xushuo.service.defaultData.DefaultWeiXinData;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.*;
import java.net.ConnectException;
import java.net.URL;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Create by zhangpe0312@qq.com on 2018/2/1.
 */
@Service
public class WeiXinUtil {

    public static Logger logger = Logger.getLogger(WeiXinUtil.class);

    @Autowired
    AccessTokenService tokenService;

    /**
     * get请求
     *
     * @param url
     * @return
     * @throws IOException
     */
    public JSONObject doGetStr(String url) throws IOException {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet(url);
        JSONObject jsonObject = null;
        HttpResponse response = httpClient.execute(httpGet);
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            String result = EntityUtils.toString(entity, "UTF-8");
            jsonObject = JSONObject.fromObject(result);
        }
        return jsonObject;
    }

    /**
     * post请求
     *
     * @param url
     * @param outStr
     * @return
     * @throws IOException
     */
    public JSONObject doPostStr(String url, String outStr) throws IOException {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);
        JSONObject jsonObject = null;
        httpPost.setEntity(new StringEntity(outStr, "UTF-8"));
        HttpResponse response = httpClient.execute(httpPost);
        String result = EntityUtils.toString(response.getEntity(), "UTF-8");
        jsonObject = JSONObject.fromObject(result);
        return jsonObject;
    }

    /**
     * 获取access_token
     * <p>
     * 返回码	说明
     * -1	系统繁忙，此时请开发者稍候再试
     * 0	请求成功
     * 40001	AppSecret错误或者AppSecret不属于这个公众号，请开发者确认AppSecret的正确性
     * 40002	请确保grant_type字段值为client_credential
     * 40164	调用接口的IP地址不在白名单中，请在接口IP白名单中进行设置
     *
     * @return
     */
    public void getAccessToken() {
        try {
            JSONObject jsonObject = null;
//            accesstoken没有过期则不获取
            AccessToken token = tokenService.getAccessToken();
            if (token != null) {
                long time = new Date().getTime() - token.getCreateTime().getTime();
                logger.info("现在还剩下的时间为  分配时间" + Integer.parseInt(token.getExpires_in()) * 1000 +
                        "  使用时间" + (time + 1000 * 60 * 30) + " 差值: " + (Integer.parseInt(token.getExpires_in()) * 1000 - (time + 1000 * 60 * 30)));
                if ((time + 1000 * 60 * 30) < Integer.parseInt(token.getExpires_in()) * 1000) {
                    logger.info("accesstoken还未过期，暂不获取 现在时间为");
                    return;
                }
            }
            jsonObject = doGetStr(DefaultWeiXinData.programmer.ACCESS_TOKEN_URL);
            /**
             * 如果获取的json为空 返回有错误代码
             */
            try {
                jsonObject.getString("errcode");
                logger.error("获取accesstoken失败");
                logger.error("请求返回错误代码：" + jsonObject.getString("errcode"));
                logger.error("请求返回错误信息：" + jsonObject.getString("errmsg"));
            } catch (JSONException e) {
                logger.info("获取accesstoken成功: \naccess_token : " + jsonObject.getString("access_token")
                        + "\ntime: " + jsonObject.getString("expires_in"));
                tokenService.
                        addAccessToken(
                                new AccessToken(jsonObject.getString("access_token")
                                        , jsonObject.getString("expires_in")));
                timingGetAccessToken();
            }
        } catch (IOException e) {
            e.printStackTrace();
            logger.error("获取accessToken失败 ：" + e);
        }
    }

    /**
     * 获取accesstoken后开始计时
     */
    public void timingGetAccessToken() {
        logger.info("开始定时刷新accessToken");
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                if (tokenService.getAccessToken() != null) {
                    tokenService.deleteAccessToken(tokenService.getAccessToken());
                }
                getAccessToken();
            }
        };

        //定时100分钟删除溢出accesstoken
        Timer timer = new Timer();
        timer.schedule(timerTask, 0, 1000 * 60 * 100);
    }

    /**
     * 创建菜单
     *
     * @param menu        菜单实例
     * @param accessToken 有效的access_token
     * @return 0表示成功，其他值表示失败
     */
    public int createMenu(Menu menu, String accessToken) throws IOException {
        int result = 0;
        // 拼装创建菜单的url
        String url = DefaultWeiXinData.menu.menu_create_url.replace("ACCESS_TOKEN", accessToken);
        // 将菜单对象转换成json字符串
        String jsonMenu = JSONObject.fromObject(menu).toString();
        // 调用接口创建菜单
        JSONObject jsonObject = doPostStr(url, jsonMenu);
        if (null != jsonObject) {
            if (0 != jsonObject.getInt("errcode")) {
                result = jsonObject.getInt("errcode");
                logger.error("创建菜单失败 errcode: " + jsonObject.getInt("errcode") +
                        "errmsg: " + jsonObject.getString("errmsg"));
            }
        }
        return result;
    }

    /**
     * 描述:  发起https请求并获取结果
     *
     * @param requestUrl    请求地址
     * @param requestMethod 请求方式（GET、POST）
     * @param outputStr     提交的数据
     * @return JSONObject(通过JSONObject.get ( key)的方式获取json对象的属性值)
     */
    public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        StringBuffer buffer = new StringBuffer();
        try {
            // 创建SSLContext对象，并使用我们指定的信任管理器初始化
            TrustManager[] tm = {new MyX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            URL url = new URL(requestUrl);
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
            httpUrlConn.setSSLSocketFactory(ssf);

            httpUrlConn.setDoOutput(true);
            httpUrlConn.setDoInput(true);
            httpUrlConn.setUseCaches(false);

            // 设置请求方式（GET/POST）
            httpUrlConn.setRequestMethod(requestMethod);

            if ("GET".equalsIgnoreCase(requestMethod))
                httpUrlConn.connect();

            // 当有数据需要提交时
            if (null != outputStr) {
                OutputStream outputStream = httpUrlConn.getOutputStream();
                // 注意编码格式，防止中文乱码
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }

            // 将返回的输入流转换成字符串
            InputStream inputStream = httpUrlConn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            bufferedReader.close();
            inputStreamReader.close();
            // 释放资源
            inputStream.close();
            inputStream = null;
            httpUrlConn.disconnect();
            jsonObject = JSONObject.fromObject(buffer.toString());
        } catch (ConnectException ce) {
            logger.error("微信相应超时");
        } catch (Exception e) {
            logger.error("HTTP错误 ：" + e);
        }
        return jsonObject;
    }


}
